package com.im.service;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.jivesoftware.smack.Chat;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.PacketCollector;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.Roster;
import org.jivesoftware.smack.RosterEntry;
import org.jivesoftware.smack.RosterGroup;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.AndFilter;
import org.jivesoftware.smack.filter.OrFilter;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.filter.PacketIDFilter;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.packet.Registration;
import org.jivesoftware.smackx.filetransfer.FileTransferListener;
import org.jivesoftware.smackx.filetransfer.FileTransferManager;
import org.jivesoftware.smackx.filetransfer.FileTransferRequest;
import org.jivesoftware.smackx.filetransfer.IncomingFileTransfer;
import org.jivesoftware.smackx.filetransfer.OutgoingFileTransfer;
import org.jivesoftware.smackx.offline.OfflineMessageManager;

import com.core.sdk.core.BaseEvent;
import com.core.sdk.core.BaseService;
import com.core.sdk.core.DoWhat;
import com.core.sdk.core.Location;
import com.core.sdk.core.LogUtil;
import com.core.sdk.event.NetWorkEvent;
import com.google.inject.Inject;
import com.im.app.ImApplication;
import com.im.db.XmppMessageDao;
import com.im.event.FileResultReivedEvent;
import com.im.event.FileResultReivedEvent.ReceivedStatus;
import com.im.event.FileResultSendEvent;
import com.im.event.FileResultSendEvent.SendStatus;
import com.im.event.FileSendEvent;
import com.im.event.FriendAddResponseEvent;
import com.im.event.FriendAddResponseEvent.ARGEE;
import com.im.event.FriendEvent;
import com.im.event.MessageResultReceivedEvent;
import com.im.event.MessageResultSendEvent;
import com.im.event.MessageSendEvent;
import com.im.event.PresenceEvent;
import com.im.event.UserRequestEvent;
import com.im.event.UserRequestEvent.OPERATE;
import com.im.event.UserResponseEvent;
import com.im.model.XmppMessage;
import com.im.util.XmppUtil;

public class SmackService extends BaseService {
	private static final String HOST = "172.16.3.110";
	private static final int PORT = 5222;
	public static String SERVICE_NAME = "@eabax";
	public static String CLIENT_RESOURCE_NAME_DEFAULT = "/Smack";
	public static String CLIENT_RESOURCE_NAME = "/Android";
	private XMPPConnection mConnection = null;
	
	
	private FileTransferManager mFileManager = null;
	private OfflineMessageManager mOfflineMsgManager = null;
	
	@Inject
	XmppMessageDao msgDao;

	/** 文件接收 */
	private final FileTransferListener mFileTransferListener = new FileTransferListener() {
		@Override
		public void fileTransferRequest(FileTransferRequest request) {
	        IncomingFileTransfer transfer = request.accept();
	       new FileReceivedThread(transfer,request){
				@Override
				public void onReceivedSuccess() {
					LogUtil.d(tag, "接收成功,path="+getSavePath());
					String toUser = getMyUserName();
					FileResultReivedEvent fre = new FileResultReivedEvent(Location.any, getFileType(), getSavePath(), getFromUser(), ReceivedStatus.finished,getDescription(),toUser);
					msgDao.createEntity(fre.getXmppMessage());
					sendEvent(fre);
				}
				
				@Override
				public void onReceivedProgress(String progress) {
					LogUtil.d(tag, "接收中,progress="+progress);
				}
				
				@Override
				public void onReceivedException(Exception e) {
					LogUtil.e(tag, "Rceived Exception:", e);
					String toUser = getMyUserName();
					FileResultReivedEvent fre = new FileResultReivedEvent(Location.any, getFileType(), getSavePath(), getFromUser(), ReceivedStatus.failed,getDescription(),toUser);
					sendEvent(fre);
				}
	       }.start();
		}
	};
	
	/** 连接监听 */
	private final ConnectionListener mConnectionListener = new ConnectionListener() {

		@Override
		public void reconnectionSuccessful() {
			LogUtil.d(tag, "Smack 重新连接成功");
		}

		@Override
		public void reconnectionFailed(Exception arg0) {
			LogUtil.d(tag, "reconnectionFailed");
		}

		@Override
		public void reconnectingIn(int arg0) {
			LogUtil.d(tag, "reconnectingIn");
		}

		@Override
		public void connectionClosedOnError(Exception e) {
			LogUtil.e(tag, "连接异常断开,Exception:",e);
		}

		@Override
		public void connectionClosed() {
			LogUtil.d(tag, "连接已经正常断开");
		}
	};

	/** 消息接收 */
	private final PacketListener packetListener = new PacketListener() {
		@Override
		public void processPacket(Packet packet) {
			if (packet instanceof Message) {
				Message msg = (Message) packet;
				String fromUser = XmppUtil.getUserNameByUserJID(msg.getFrom());
				String toUser = XmppUtil.getUserNameByUserJID(msg.getTo());
				XmppMessage xm = new XmppMessage(msg.getBody(),fromUser,toUser,false,XmppMessage.MSG_TYPE_TEXT);
				msgDao.createEntity(xm);
				MessageResultReceivedEvent evt = new MessageResultReceivedEvent(Location.any, xm);
				sendEvent(evt);
			} else if (packet instanceof Presence) {
				Presence presence = (Presence) packet;
				String from = presence.getFrom();// 发送方
//				String to = presence.getTo();// 接收方
				PresenceEvent pevt = new PresenceEvent(Location.any, presence);
				boolean needSend = true;
				if (presence.getType().equals(Presence.Type.subscribe)) {// 好友申请
					LogUtil.d(tag, "收到" + from + "的好友申请请求");
				} else if (presence.getType().equals(Presence.Type.subscribed)) {// 同意添加好友
					LogUtil.d(tag, from + "同意了我的好友申请");
				} else if (presence.getType().equals(Presence.Type.unsubscribe)) {// 拒绝添加好友和删除好友
					LogUtil.d(tag, from + "拒绝了我的好友申请");
				} else if (presence.getType().equals(Presence.Type.unsubscribed)) {// 拒绝添加好友和删除好友
					LogUtil.d(tag, from + "删除了我");
				} else if (presence.getType().equals(Presence.Type.unavailable)) {// 好友下线
					LogUtil.d(tag, from + "已经下线");
				} else if (presence.getType().equals(Presence.Type.available)) {// 好友上线
					LogUtil.d(tag, from + "已经上线");
				} else if (presence.getType().equals(Presence.Type.error)) { // error
					LogUtil.d(tag, from + "出错了");
					needSend = false;
				} else {
					LogUtil.d(tag, from + "unknow for status:" + presence.getType().name());
					needSend = false;
				}
				if (needSend) {
					sendEvent(pevt);
				}
			}
		}
	};

	/** 消息发送 */
	private final PacketListener packetSendListener = new PacketListener() {
		@Override
		public void processPacket(Packet packet) {
			if (packet instanceof Message) {
				Message msg = (Message) packet;
				String fromUser = XmppUtil.getUserNameByUserJID(msg.getFrom());
				String toUser = XmppUtil.getUserNameByUserJID(msg.getTo());
				XmppMessage xm = new XmppMessage(msg.getBody(),fromUser,toUser,true,XmppMessage.MSG_TYPE_TEXT);
				msgDao.createEntity(xm);
				MessageResultSendEvent evt = new MessageResultSendEvent(Location.any, xm);
				sendEvent(evt);
				
			} else if (packet instanceof Presence) {

			}
		}
	};

	private ImApplication getImApplication() {
		return ((ImApplication) getApplicationContext());
	}

	private void setUserJID(String jid) {
		getImApplication().setUserJID(jid);
	}

	private void setRoster(Roster roster) {
		getImApplication().setRoster(roster);
	}

	@Override
	protected void doCreate() {
//		SmackAndroid.init(getApplicationContext());
		mConnection = new XMPPConnection(getXmppConnectionConfig());
	}

	private ConnectionConfiguration getXmppConnectionConfig() {
		ConnectionConfiguration config = new ConnectionConfiguration(HOST, PORT);
		// config.setSelfSignedCertificateEnabled(true);
		// config.setSecurityMode(ConnectionConfiguration.SecurityMode.required);
		config.setReconnectionAllowed(true);// 断开后自动重连
		config.setRosterLoadedAtLogin(true);
		config.setSendPresence(true);
		config.setDebuggerEnabled(false);
		config.setSASLAuthenticationEnabled(false);
		return config;
	}

	private void addListeners() {
//		mAccoutManage = mConnection.getAccountManager();
		mFileManager = new FileTransferManager(mConnection);
//		FileTransferNegotiator.setServiceEnabled(mConnection, true);
		mFileManager.addFileTransferListener(mFileTransferListener);
		mConnection.addConnectionListener(mConnectionListener);

		// IQ, Message, Presence, AuthMechanism, Response,RosterPacket
		PacketFilter msgFilter = new PacketTypeFilter(Message.class);
		PacketFilter presenceFilter = new PacketTypeFilter(Presence.class);
		OrFilter orFilter = new OrFilter(msgFilter, presenceFilter);
		mConnection.addPacketListener(packetListener, orFilter);
		mConnection.addPacketSendingListener(packetSendListener, orFilter);
		
		mOfflineMsgManager = new OfflineMessageManager(mConnection);
		
	}

	@Override
	protected void doDestroy() {
		closeConnect();
		LogUtil.d(tag, "SmackService Destroied");
		android.os.Process.killProcess(android.os.Process.myPid());
	}

	@Override
	protected void doExecuteEvent(BaseEvent evt) {
		super.doExecuteEvent(evt);
		if (evt instanceof UserRequestEvent) {
			UserRequestEvent event = (UserRequestEvent) evt;
			if (event.getOp() == OPERATE.request_reg) {
				procressRegister(event);
			} else if (event.getOp() == OPERATE.request_login) {
				procressLogin(event);
			} else if (event.getOp() == OPERATE.request_user_list) {
				procressGetUserList(event);
			} else if (event.getOp() == OPERATE.request_logout) {
				procressLogout();
			}
		} else if (evt instanceof MessageSendEvent) {
			MessageSendEvent event = (MessageSendEvent) evt;
			procressSendMsg(event);
		} else if (evt instanceof FriendAddResponseEvent) {// 主要是处理别人添加我为好友的回复(是否同意)
			FriendAddResponseEvent pe = (FriendAddResponseEvent) evt;
			procressAddFriend(pe);
		} else if (evt instanceof FriendEvent) {
			FriendEvent fe = (FriendEvent) evt;
			procressFriendEvent(fe);
		}else if(evt instanceof FileSendEvent){
			FileSendEvent fe = (FileSendEvent)evt;
			try {
				sendFile(fe.getPath(), fe.getToUserJid(),fe.getDescription());
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	/** 关闭连接 */
	private void closeConnect() {
		if (mConnection != null && mConnection.isConnected()) {
			mConnection.disconnect();
			LogUtil.d(tag, "Smack Disconnected");
		}
		mConnection = null;
	}

	/** 获取用户列表 */
	private void procressGetUserList(UserRequestEvent event) {
		if(mConnection == null){
			LogUtil.e(tag, "mConnection is null");
			return ;
		}
		Collection<RosterEntry> list = mConnection.getRoster().getEntries();
		UserResponseEvent responseEvent = new UserResponseEvent(event.getFrom(), event.getOp());
		responseEvent.setData(list);
		sendEvent(responseEvent);
	}

	/** 用户登录 */
	private void procressLogin(UserRequestEvent event) {
		String u = event.getUserId();
		String p = event.getPassword();
		UserResponseEvent responseEvent = new UserResponseEvent(event.getFrom(), event.getOp());
		try {
			openConnection();
			mConnection.login(u, p);
			if (!mConnection.isAuthenticated()) {
				throw new RuntimeException("Smack login failed");
			}
			//获取离线消息
			loadOfflineMessage();
			Presence presence = new Presence(Presence.Type.available);
			mConnection.sendPacket(presence);
			String user = mConnection.getUser();
			LogUtil.d(tag, "Smack login successful for userJID:" + user);
			responseEvent.setResponseCode(UserResponseEvent.RESPONSE_LOGIN_SUC);
		} catch (Exception e) {
			responseEvent.setResponseCode(UserResponseEvent.RESPONSE_LOGIN_FAI);
			LogUtil.e(tag, "Smack login Exception:", e);
		}
		sendEvent(responseEvent);
		setUserJID(mConnection.getUser().replace(CLIENT_RESOURCE_NAME_DEFAULT, ""));
		setRoster(mConnection.getRoster());
		printRoster();
	}

	/** 打开连接 */
	private void openConnection() throws XMPPException {
		if(mConnection.isConnected())
			return ;
		mConnection.connect();
		if (!mConnection.isConnected()) {
			throw new RuntimeException("Smack can't connect");
		}
		SERVICE_NAME = mConnection.getServiceName();
		addListeners();
	}

	/** 打印所有分组有组中所包含的用户 */
	private void printRoster() {
		Collection<RosterGroup> groups = mConnection.getRoster().getGroups();
		for (RosterGroup group : groups) {
			LogUtil.d(tag, "groupName:" + group.getName() + " count:" + group.getEntryCount());
			Collection<RosterEntry> entries = group.getEntries();
			for (RosterEntry entry : entries) {
				LogUtil.d(tag, "entry.userJID=" + entry.getUser());
			}
		}
	}

	/** 退出登录 */
	private void procressLogout() {
		Presence presence = new Presence(Presence.Type.unavailable);
		mConnection.sendPacket(presence);

		closeConnect();
		// 停止自己
		this.stopSelf();
	}

	/** 用户注册 */
	private void procressRegister(UserRequestEvent event) {
		String userName = event.getUserId();
		String password = event.getPassword();
		try {
			openConnection();
			Registration reg = new Registration();
			reg.setType(IQ.Type.SET);
			reg.setTo(mConnection.getServiceName());
			Map<String,String> attributes = new HashMap<String,String>();
			attributes.put("username", userName);
			attributes.put("password", password);
			if (event.getName() != null) {
				attributes.put("name", event.getName());
			}
			if (event.getEmail() != null) {
				attributes.put("email", event.getEmail());
			}
			reg.setAttributes(attributes);

			PacketFilter filter = new AndFilter(new PacketIDFilter(reg.getPacketID()), new PacketTypeFilter(IQ.class));
			PacketCollector collector = mConnection.createPacketCollector(filter);
			mConnection.sendPacket(reg);
			IQ result = (IQ) collector.nextResult(SmackConfiguration.getDefaultPacketReplyTimeout());
			collector.cancel();// 停止请求results（是否成功的结果）
			UserResponseEvent responseEvent = new UserResponseEvent(event.getFrom(), event.getOp());

			if (result == null) {
				responseEvent.setResponseCode(UserResponseEvent.RESPONSE_REG_FAI);// 服务器没有返回结果
			} else if (result.getType() == IQ.Type.ERROR) {
				if (result.getError().toString().equalsIgnoreCase("conflict(409)")) {
					responseEvent.setResponseCode(UserResponseEvent.RESPONSE_REG_EXISTS);// 这个账号已经存在
				} else {
					responseEvent.setResponseCode(UserResponseEvent.RESPONSE_REG_FAI);// 注册失败
				}
			} else if (result.getType() == IQ.Type.RESULT) {
				responseEvent.setResponseCode(UserResponseEvent.RESPONSE_REG_SUC);
			}
			sendEvent(responseEvent);
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
	

//	/** 用户注册 */
//	private void procressRegister(UserRequestEvent event) {
//		String username = event.getUserId();
//		String password = event.getPassword();
//		Map<String,String> attributes = new HashMap<String,String>();
//		String name = event.getName();
//		String email = event.getEmail();
//		if(name != null)
//			attributes.put("name", name);
//		if(email != null)
//			attributes.put("email", email);
//		try {
//			openConnection();
//			mConnection.getAccountManager().createAccount(username, password, attributes);
//		} catch (XMPPException e) {
//			e.printStackTrace();
//		}
//	}

	/** 发送消息 */
	private void procressSendMsg(MessageSendEvent event) {
		String userJID = event.getUserJID();
		Chat chat = mConnection.getChatManager().createChat(userJID, null);
		try {
			if (event.getMsg() != null) {
				chat.sendMessage(event.getMsg());
			} else if (event.getText() != null) {
				chat.sendMessage(event.getText());
			}
		} catch (Exception e) {
			LogUtil.e(tag, "Smack send msg Exception:", e);
		}
	}
	
	

	/** 处理别人加我为好友的请求 */
	private void procressAddFriend(FriendAddResponseEvent event) {
		if (event.getArgee() == ARGEE.yes || event.getArgee() == ARGEE.yes_add) {
			Presence status = new Presence(Presence.Type.subscribed);
			mConnection.sendPacket(status);
		} else {
			Presence status = new Presence(Presence.Type.unsubscribe);
			mConnection.sendPacket(status);
		}

	}

	/** 添加别人为好友 */
	private void procressFriendEvent(FriendEvent event) {
		String fid = event.getFriendId();
		if (event.getOp() == FriendEvent.Option.add) {
			String name = event.getName() == null ? fid : event.getName();
			String[] groups = event.getGroup() != null ? new String[] { event.getGroup() } : null;
			String jid = fid + SERVICE_NAME;
			addUser(jid, name, groups);
		}
	}
	
	/** 文件发送 */
	private void sendFile(String filePath,String toUserJID,String description) throws Exception{
		OutgoingFileTransfer transfer = mFileManager.createOutgoingFileTransfer(toUserJID);
		File f = new File(filePath);
		transfer.sendFile(f.getName(), f.length(), "send File Progress", new FileSendProgress(f,toUserJID,description){

			@Override
			public void onSendSuccess() {
				LogUtil.d(tag, "File "+getFile().getName()+"发送成功");
				String fromUser = getMyUserName();
				FileResultSendEvent fsre = new FileResultSendEvent(Location.any, getFileType(),getFilePath() , getToUserJID(), SendStatus.finished,getDescription(),fromUser);
				msgDao.createEntity(fsre.getXmppMessage());
				sendEvent(fsre);
			}

			@Override
			public void onSendProgress(String progress) {
				LogUtil.d(tag, "文件发送中,进度="+progress);
			}

			@Override
			public void onSendException(Exception e) {
				LogUtil.e(tag, "File "+getFile().getName()+"发送失败!Exception:",e);
				String fromUser = getMyUserName();
				FileResultSendEvent fsre = new FileResultSendEvent(Location.any, getFileType(),getFilePath() , getToUserJID(), SendStatus.failed,getDescription(),fromUser);
				sendEvent(fsre);
			}
			
		});
		
		//transfer.sendFile(f, "send File progress");
	}
	
	/** 将离线消息插入到数据库 */
	@Override
	protected void doExecuteDoWhat(DoWhat doWhat) {
		super.doExecuteDoWhat(doWhat);
		if(doWhat.getWhat() == 1){
			ArrayList<Message> msgList = (ArrayList<Message>)doWhat.getObj();
			insertOfflineMessage(msgList);
		}
	}
	
	private void insertOfflineMessage(ArrayList<Message> msgList){
		if(msgList == null || msgList.size() == 0){
			return ;
		}
		for (Message msg : msgList) {
			String fromUser = XmppUtil.getUserNameByUserJID(msg.getFrom());
			String toUser = XmppUtil.getUserNameByUserJID(msg.getTo());
			XmppMessage xm = new XmppMessage(msg.getBody(),fromUser,toUser,false,XmppMessage.MSG_TYPE_TEXT);
			msgDao.createEntity(xm);
		}
	}
	
	/** 获取离线消息 */
	private void loadOfflineMessage(){
		try {
			int msgCount = mOfflineMsgManager.getMessageCount();
			if(msgCount <=0 )
				return ;
			Iterator<Message> iterMsg = mOfflineMsgManager.getMessages();
			if(iterMsg == null)
				return ;
			ArrayList<Message> msgList = new ArrayList<Message>();
			while(iterMsg.hasNext()){
				Message msg = iterMsg.next();
				msgList.add(msg);
			}
			DoWhat doWhat = new DoWhat(1, msgList);
			submitDoWhat(doWhat);
			LogUtil.d(tag, "成功收到"+msgCount+"条离线消息!");
			mOfflineMsgManager.deleteMessages();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}

	// ====================================group-manager-begin==========================================
	/** 创建一个组 */
	private boolean createGroup(String groupName) {
		RosterGroup rg = mConnection.getRoster().createGroup(groupName);
		return rg != null;
	}

	/** 获取所有组列表 */
	private Collection<RosterGroup> getAllGroups() {
		return mConnection.getRoster().getGroups();
	}

	/** 获取所有用户列表 */
	@SuppressWarnings("unused")
	private Collection<RosterEntry> getAllUsers() {
		return mConnection.getRoster().getEntries();
	}

	/** 添加用户到某个分组 */
	private boolean addUser(String userJID, String name, String[] groups) {
		boolean suc = false;
		try {
			mConnection.getRoster().createEntry(userJID, name, groups);
			suc = true;
		} catch (XMPPException e) {
			e.printStackTrace();
		}
		return suc;
	}

	private boolean removeUser(String userJID) {
		boolean suc = false;
		try {
			String user = userJID.split("@")[0];
			RosterEntry entry = mConnection.getRoster().getEntry(user);
			mConnection.getRoster().removeEntry(entry);
			suc = true;
		} catch (XMPPException e) {
			e.printStackTrace();
		}
		return suc;
	}

	// ====================================group-manager-End==========================================
	/** 网络发生变化 */
	@Override
	protected void onNetworkStateChanged(NetWorkEvent evt) {
		super.onNetworkStateChanged(evt);
	}
	
	protected String getMyUserJID(){
		return ((ImApplication) getApplicationContext()).getUserJID();
	}
	private String getMyUserName(){
		return XmppUtil.getUserNameByUserJID(getMyUserJID());
	}

}
